﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using SharedObjects;

namespace TheGameLib
{
	/// <summary>
	/// This class is a session container for connected players.
	/// </summary>
	public class AgentSessionObject : IDisposable
	{
		public event EventHandler SessionDisconnect;
		public event EventHandler<MailNotifyEventArgs> NewMail;
		public event EventHandler<BankTransactionNotifyEventArgs> NewBankTransaction;
		public Guid SessionId { get; private set; }
		
		private Agent _agentInDb;
		public Agent AgentInDb 
		{ 
			get
			{
				if (_agentInDb != null)
				{
					return _agentInDb;
				}
				throw new FaultException("AgentSession: agentInDb object null.");
			}
		}

        public DateTime SessionStartTime { get; private set; }
		public DateTime LastSessionActivity { get; private set; }
		public int Luck { get; private set; } //modifier for all chance based actions to remove uniqueness of performance from gameplay.

		public List<AgentConnection> Connections { get; private set; }

		public AgentSessionObject(Agent agentInDb)
		{
			_agentInDb = agentInDb;
			SessionStartTime = DateTime.Now;
			Connections = new List<AgentConnection>();
			LastSessionActivity = DateTime.Now;
			SessionId = Guid.NewGuid();
			Luck = GetLuckValue();
		}

		private int GetLuckValue()
		{
			Random rand = new Random(Environment.TickCount);
			int result = 0;
			for(int i = 0; i < 3; i++)
				result += rand.Next(1, 6);
			return (int)((result / 3.0) - 10.5); //(-10 -> + 10)
		}

		public void UpdateSessionLifetime()
		{
			LastSessionActivity = DateTime.Now;
		}

		public void UpdateSessionLifetime(Agent updatedAgent)
		{
			if(updatedAgent != null && updatedAgent.Id == _agentInDb.Id)
				_agentInDb = updatedAgent;
			UpdateSessionLifetime();
		}

		/// <summary>
		/// Connects the agent to a computer system.
		/// </summary>
		/// <param name="hops">the route of nodes used for the connection</param>
		/// <param name="securitySystems">list of secsys IDs, cannot be obtained within ASO, no database here.</param>
		/// <param name="connectionId"></param>
		/// <returns></returns>
		public bool Connect(List<ulong> hops, List<ulong> securitySystems, out Guid? connectionId)
		{
			connectionId = null;
			if (Connections.Where(it => it.TargetSystemId == hops.Last()).Count() > 0)
				return false;
			AgentConnection c = new AgentConnection(hops, securitySystems);
			Connections.Add(c);
			connectionId = c.ConnectionId;
			return true;
		}

		public AgentConnection GetAgentConnection(Guid connectionId)
		{
			return Connections.Where(it => it.ConnectionId == connectionId).FirstOrDefault();
		}

		public AgentConnection GetAgentConnectionByTargetSystem(ulong systemId)
		{
			return Connections.Where(it => it.TargetSystemId == systemId).FirstOrDefault();
		}

		public void SessionDisconnected()
		{
			if (SessionDisconnect != null)
				SessionDisconnect(this, null);
		}

		public void Dispose()
		{
		}

		public void NotifyNewEmail(string sourceEmailAddress, string receivingServername)
		{
			if (NewMail != null)
				NewMail(this, new MailNotifyEventArgs { SourceEmailAddress = sourceEmailAddress, ReceivingServerName = receivingServername });
		}

		public void NotifyBankTransaction(long amount, string sendingAccount, string receivingAccount, DateTime transactionDate)
		{
			if (NewBankTransaction != null)
				NewBankTransaction(this, new BankTransactionNotifyEventArgs {Amount = amount, ReceivingAccount = receivingAccount, SendingAccount = sendingAccount, TransactionDate = transactionDate});
		}
	}

	public enum SystemConnectionState
	{
		Disconnected,	//default state
		Connected,		//connected to system, secsys ui normally being displayed, no user interaction taken yet
		Bypassing,		//user started bypassing secsystems
		Bypassed,		//user completed bypassing secsystems
		LoggingIn,		//user requested login into system
		LoggedIn		//user successfully logged into system
	}

	public enum TraceState
	{
		Idle,			//default state
		TraceRunning,	//a trace is running from the user's current connection target back to him.
		TraceFinished	//a trace has completed and found the agent.
	}

	public class TraceEventArgs : EventArgs
	{
		public int RemainingMilliseconds { get; set; }
	}

	public class TraceEndedEventArgs : EventArgs
	{
		public Guid ConnectionId { get; set;}
		public bool TraceTimeElapsed { get; set; }
	}

	public class MailNotifyEventArgs :EventArgs
	{
		public string SourceEmailAddress { get; set; }
		public string ReceivingServerName { get; set; }
	}

	public class BankTransactionNotifyEventArgs : EventArgs
	{
		public long Amount { get; set;}
		public string SendingAccount { get; set;}
		public string ReceivingAccount { get; set;}
		public DateTime TransactionDate { get; set; }
	}
}
